package cn.dinkevin.xui.widget.input;

import android.content.Context;
import android.text.Layout;
import android.util.AttributeSet;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.widget.EditText;
import android.widget.TextView;

import java.lang.reflect.Field;

import cn.dinkevin.xui.util.LogUtil;

/**
 * 禁用长按弹出复制、选择等菜单
 * Created by ChengPengFei on 2017/3/27 0027.</br>
 * Copyright ©2017 juziwl, All Rights Reserved.
 */

public class NoMenuEditText extends EditText {

    //滑动距离的最大边界
    private int mOffsetHeight;

    //是否到顶或者到底的标志
    private boolean mBottomFlag = false;

    public NoMenuEditText(Context context) {
        super(context);
        init();
    }

    @Override
    protected boolean getDefaultEditable() {
        return true;
    }

    public NoMenuEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public NoMenuEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        this.setCustomSelectionActionModeCallback(new ActionModeCallbackInterceptor());
        this.setLongClickable(false);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int paddingTop;
        int paddingBottom;
        int mHeight;
        int mLayoutHeight;

        //获得内容面板
        Layout mLayout = getLayout();
        //获得内容面板的高度
        mLayoutHeight = mLayout.getHeight();
        //获取上内边距
        paddingTop = getTotalPaddingTop();
        //获取下内边距
        paddingBottom = getTotalPaddingBottom();

        //获得控件的实际高度
        mHeight = getHeight();

        //计算滑动距离的边界
        mOffsetHeight = mLayoutHeight + paddingTop + paddingBottom - mHeight;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN)
            //如果是新的按下事件，则对mBottomFlag重新初始化
            mBottomFlag = false;
        //如果已经不要这次事件，则传出取消的信号，这里的作用不大
        if (mBottomFlag)
            event.setAction(MotionEvent.ACTION_CANCEL);
        return super.dispatchTouchEvent(event);
    }

    @Override
    protected void onScrollChanged(int horzi, int vertical, int oldHoriz, int oldVert) {
        super.onScrollChanged(horzi, vertical, oldHoriz, oldVert);
        if (vertical == mOffsetHeight || vertical == 0) {
            //这里触发父布局或祖父布局的滑动事件
            getParent().requestDisallowInterceptTouchEvent(false);
            mBottomFlag = true;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        // 禁用长按弹出菜单
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            try {
                Field editorField = TextView.class.getDeclaredField("mEditor");
                editorField.setAccessible(true);
                Object editorObject = editorField.get(this);

                Class editorClass = Class.forName("android.widget.Editor");
                Field mInsertionControllerEnabledField = editorClass.getDeclaredField("mInsertionControllerEnabled");
                mInsertionControllerEnabledField.setAccessible(true);
                mInsertionControllerEnabledField.set(editorObject, false);

                Field mSelectionControllerEnabled = editorClass.getDeclaredField("mSelectionControllerEnabled");
                mSelectionControllerEnabled.setAccessible(true);
                mSelectionControllerEnabled.set(editorObject, false);

                Field mIgnoreActionUpEvent = editorClass.getDeclaredField("mIgnoreActionUpEvent");
                mIgnoreActionUpEvent.setAccessible(true);
                mIgnoreActionUpEvent.set(editorObject, true);
            }
            catch (Exception ignored) {
                // ignore exception here
                LogUtil.e("editText disable copy menu",ignored.getMessage());
            }
        }

        boolean result = super.onTouchEvent(event);
        //如果是需要拦截，则再拦截，这个方法会在onScrollChanged方法之后再调用一次
        if (!mBottomFlag)
            getParent().requestDisallowInterceptTouchEvent(true);
        return result;
    }

    /**
     * Prevents the action bar (top horizontal bar with cut, copy, paste, etc.)
     * from appearing by intercepting the callback that would cause it to be
     * created, and returning false.
     */
    private class ActionModeCallbackInterceptor implements ActionMode.Callback {

        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            return false;
        }

        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return false;
        }

        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            return false;
        }

        public void onDestroyActionMode(ActionMode mode) { }
    }
}
